package com.alex.common.aop;


import com.alex.common.beans.ResultBean;
import com.alex.exceptions.CheckException;
import com.alex.exceptions.NoPermissionException;
import com.alex.exceptions.UnloginException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


/**
 * 处理和包装异常
 *
 * @time:2019年01月01日21:10:36
 */
@Slf4j
@Aspect
@Component
//@Order(-99)
@SuppressWarnings("all")

public class ControllerAOP {
    //1


    private static final Logger logger = LoggerFactory.getLogger(com.alex.common.aop.ControllerAOP.class);

    @Pointcut("execution(com.alex.common.beans.ResultBean *(..))")
    public void controllerMethod() {
    }

    @Around("controllerMethod()")
    public Object handlerControllerMethod(ProceedingJoinPoint pjp) {

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) Objects.requireNonNull(requestAttributes)
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
        ResultBean<?> result = null;
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        try {
            result = (ResultBean<?>) pjp.proceed();
        } catch (Throwable e) {

            result = handlerException(pjp, e);
        }
        return result;
    }

    private ResultBean<?> handlerException(ProceedingJoinPoint pjp, Throwable e) {
        ResultBean<?> result = new ResultBean();
        // 登陆异常 1
        if (e instanceof UnloginException) {
            result.setMsg("Unlogin");
            result.setCode(ResultBean.NO_LOGIN);
        }
        // 没有权限 2
        else if (e instanceof NoPermissionException) {
            result.setMsg("NO PERMISSION: " + e.getMessage());
            result.setCode(ResultBean.NO_PERMISSION);
        }
        // 已知异常 3
        else if (e instanceof CheckException) {
            result.setMsg(e.getLocalizedMessage());
            result.setCode(ResultBean.CHECK_FAIL);
        } else {
            logger.error(pjp.getSignature() + " error ", e);
            result.setMsg("操作失败,请稍后重试");
            result.setCode(ResultBean.UNKNOWN_EXCEPTION);
        }
        return result;
    }


    /**
     * 转换request 请求参数
     *
     * @param joinPoint
     * @param method
     * @return
     */
    private Map<String, Object> convertMap(JoinPoint joinPoint, Method method) {
        // 参数值
        Object[] args = joinPoint.getArgs();
        ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
        String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < Objects.requireNonNull(parameterNames).length; i++) {
            if (args == null || args.length == 0) {
                paramMap.put(parameterNames[i], "none");
                continue;
            }
            String argsStr = "";
            if (args[i] != null) {
                argsStr = JSON.toJSONString(args[i]);
            }
            String param = "";
            if (parameterNames[i] != null) {
                param = parameterNames[i];
            }

            paramMap.put(param, argsStr);
        }
        return paramMap;
    }

    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
    private String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer stringBuffer = new StringBuffer();
        for (StackTraceElement stet : elements) {
            stringBuffer.append(stet + "\n");
        }
        return exceptionName + ":" + exceptionMessage + "\n\t" + stringBuffer.toString();
    }

}
